#include "Plansza.h"
#include <allegro5/allegro_primitives.h>
#include <algorithm>
#include <string>
#include <cmath>

PlanszaWirtualna::PlanszaWirtualna(int rozmiarBokuPlanszy, bool_ pionyPoczatkowe)
:rozmiarBokuPlanszy(rozmiarBokuPlanszy)
{
	if(rozmiarBokuPlanszy>0)
		plansza.resize(rozmiarBokuPlanszy*rozmiarBokuPlanszy,PUSTE); //Ustalamy rozmiar planszy
	else
		throw WyjatekBlednyArgument("zly rozmiar planszy!");
	
	WSPOLRZEDNE_PLANSZY::maxX=rozmiarBokuPlanszy; //do obslugi bledow
	WSPOLRZEDNE_PLANSZY::maxY=rozmiarBokuPlanszy; //do obslugi bledow
	if(pionyPoczatkowe)
	for (int i=0;i<rozmiarBokuPlanszy;i++) //Wypelniamy plansze poczatkowymi wartosciami
	{
		plansza[Indeks(WSPOLRZEDNE_PLANSZY(i,0))]=GRACZ_1;
		plansza[Indeks(WSPOLRZEDNE_PLANSZY(i,rozmiarBokuPlanszy-1))]=GRACZ_2;		
	}
}

void Plansza::GenerujPodpowiedzi(TURA gracz)
{
	int x=zaznaczenie.x;
	int y=zaznaczenie.y;

	podpowiedzi.clear();
	if(zaznaczaj)
	if(plansza[Indeks(WSPOLRZEDNE_PLANSZY(x,y))]==gracz)
				for (int dx=-1;dx<2;dx++)
					for(int dy=-1;dy<2;dy++)
						if(x+dx!=-1&&x+dx!=rozmiarBokuPlanszy&&y+dy!=-1&&y+dy!=rozmiarBokuPlanszy)
							if(plansza[Indeks(WSPOLRZEDNE_PLANSZY(x+dx,y+dy))]==PUSTE)
							{
								int tempX=x;
								int tempY=y;
								bool_ ruchMozliwy=false;
								while(!ruchMozliwy&&tempX+dx!=-1&&tempX+dx!=rozmiarBokuPlanszy&&tempY+dy!=-1&&tempY+dy!=rozmiarBokuPlanszy)
								{
									tempX+=dx;
									tempY+=dy;
									ruchMozliwy=SprawdzRuch(WSPOLRZEDNE_PLANSZY(x,y),WSPOLRZEDNE_PLANSZY(tempX,tempY),gracz);
								}
								if (ruchMozliwy)
								{
								
									podpowiedzi.push_back(WSPOLRZEDNE_PLANSZY(tempX,tempY));							

								}

							}


}

Plansza::Plansza(int rozmiarBokuPlanszy, int pozycjaXNaEkranie, int pozycjaYNaEkranie, int szerokoscPola, bool_ pionyPoczatkowe)
: PlanszaWirtualna(rozmiarBokuPlanszy,pionyPoczatkowe),  pozycjaXNaEkranie(pozycjaXNaEkranie),
  pozycjaYNaEkranie(pozycjaYNaEkranie), szerokoscPola(szerokoscPola)
{	
	//Inicjalizacja
	podswietlaj=false;
	zaznaczaj=false;
	podpowiadaj=false;
	
	//al_acknowledge_resize(al_get_current_display());
}

std::vector<POLE>::size_type PlanszaWirtualna::Indeks(WSPOLRZEDNE_PLANSZY wspolrzedne)
{
	int indeks= wspolrzedne.x+wspolrzedne.y*rozmiarBokuPlanszy;
	if ((wspolrzedne.x<0||wspolrzedne.x>=rozmiarBokuPlanszy)||(wspolrzedne.y<0||wspolrzedne.y>=rozmiarBokuPlanszy))
		throw WyjatekPrzekroczenieGranicyIndeksu("indeks planszy, wspolrzedne"+wspolrzedne.ToString());
	return indeks;
}

WSPOLRZEDNE_PLANSZY Plansza::WspolrzednePlanszy(WSPOLRZEDNE_EKRANOWE wspolrzedne)
{
	return WSPOLRZEDNE_PLANSZY(
		(wspolrzedne.x - pozycjaXNaEkranie)/szerokoscPola,
		(wspolrzedne.y - pozycjaYNaEkranie)/szerokoscPola);	
}

WSPOLRZEDNE_EKRANOWE Plansza::WspolrzedneEkranowe(WSPOLRZEDNE_PLANSZY wspolrzedne)
{
	return WSPOLRZEDNE_EKRANOWE(
		wspolrzedne.x*szerokoscPola+pozycjaXNaEkranie,
		wspolrzedne.y*szerokoscPola+pozycjaYNaEkranie);
}
POLE PlanszaWirtualna::Pole(WSPOLRZEDNE_PLANSZY wspolrzedne)
{
	return plansza[Indeks(wspolrzedne)];
}
void Plansza::Rysuj()
{
	//Rysoawnie planszy
	al_draw_rectangle(KrawedziePlanszy().first.x-1,KrawedziePlanszy().first.y-1, KrawedziePlanszy().second.x,KrawedziePlanszy().second.y,al_map_rgb(99,99,99),2);
	for(int x=0;x<rozmiarBokuPlanszy;x++)
		for (int y=0;y<rozmiarBokuPlanszy;y++)
		{
			WSPOLRZEDNE_PLANSZY wsp1(x,y); //lewy gorny rog
			WSPOLRZEDNE_PLANSZY wsp2(x+1,y+1); //prawy dolny
			//Rysowanie siatki
			al_draw_filled_rectangle(WspolrzedneEkranowe(wsp1).x,WspolrzedneEkranowe(wsp1).y, 
							WspolrzedneEkranowe(wsp2).x,WspolrzedneEkranowe(wsp2).y,
							(x+y)%2==0?al_map_rgb(83,111,48):al_map_rgb(7,31,59));

			POLE przetwarzanePole=Pole(WSPOLRZEDNE_PLANSZY(x,y));
			if(przetwarzanePole!=PUSTE) //Rysowanie graczy
				al_draw_filled_circle((WspolrzedneEkranowe(wsp1).x+WspolrzedneEkranowe(wsp2).x)/2,
				(WspolrzedneEkranowe(wsp1).y+WspolrzedneEkranowe(wsp2).y)/2,szerokoscPola/2,
				przetwarzanePole==GRACZ_1?al_map_rgb(0,255,0):al_map_rgb(0,0,255));
		}



		//Rysowanie zaznaczenia i podswietlenia 
		if (zaznaczaj)
			al_draw_rectangle(WspolrzedneEkranowe(zaznaczenie).x,WspolrzedneEkranowe(zaznaczenie).y,
			WspolrzedneEkranowe(zaznaczenie+1).x,WspolrzedneEkranowe(zaznaczenie+1).y,
			al_map_rgb(255,255,0),2);
		if (podswietlaj)
			al_draw_rectangle(WspolrzedneEkranowe(podswietlenie).x,WspolrzedneEkranowe(podswietlenie).y,
			WspolrzedneEkranowe(podswietlenie+1).x,WspolrzedneEkranowe(podswietlenie+1).y,
			al_map_rgb(0,255,255),2);
		if (podpowiadaj)
		{
			for(std::vector<WSPOLRZEDNE_PLANSZY>::iterator itpod=podpowiedzi.begin();itpod!=podpowiedzi.end();itpod++)
			{
				al_draw_rectangle(WspolrzedneEkranowe(*itpod).x,WspolrzedneEkranowe(*itpod).y,
				WspolrzedneEkranowe(*itpod+1).x,WspolrzedneEkranowe(*itpod+1).y,
				al_map_rgb(200,200,200),2);
			}
		}
		//podpowiadaj=false;

}

bool_ PlanszaWirtualna::UstawPiona(WSPOLRZEDNE_PLANSZY wsp, TURA gracz)
{
	if(Pole(wsp)==PUSTE)
	{
		plansza[Indeks(wsp)]=gracz;
		return true;
	}
	return false;
}

std::pair<WSPOLRZEDNE_EKRANOWE,WSPOLRZEDNE_EKRANOWE> Plansza::KrawedziePlanszy()
{
	return std::make_pair(WSPOLRZEDNE_EKRANOWE(pozycjaXNaEkranie,pozycjaYNaEkranie),
		WSPOLRZEDNE_EKRANOWE(pozycjaXNaEkranie+szerokoscPola*rozmiarBokuPlanszy,pozycjaYNaEkranie+szerokoscPola*rozmiarBokuPlanszy));
}

void Plansza::UstawPodswietlenie(WSPOLRZEDNE_EKRANOWE wspolrzedne)
{
	podswietlenie=WspolrzednePlanszy(wspolrzedne);
}

void Plansza::UstawZaznaczenie(WSPOLRZEDNE_EKRANOWE wspolrzedne)
{
	zaznaczenie=WspolrzednePlanszy(wspolrzedne);
}

PlanszaWirtualna::PlanszaWirtualna(const PlanszaWirtualna & zrodlo)
:plansza(zrodlo.plansza)
{
	
	rozmiarBokuPlanszy=zrodlo.rozmiarBokuPlanszy;
}

WSPOLRZEDNE_PLANSZY Plansza::PobierzZaznaczenie()
{
	return zaznaczenie;
}

WSPOLRZEDNE_PLANSZY Plansza::PobierzPodswietlenie()
{
	return podswietlenie;
}
bool_ PlanszaWirtualna::SprawdzRuch(WSPOLRZEDNE_PLANSZY zrodlo, WSPOLRZEDNE_PLANSZY cel, TURA gracz)
{
    //ilosc krokow do przejscia
	int krokiX=abs(zrodlo.x-cel.x);
	int krokiY=abs(zrodlo.y-cel.y);
	//Kierunki ruchu
	int dx= krokiX!=0? ((zrodlo.x-cel.x)>0 ?-1:1) :0;
	int dy= krokiY!=0? ((zrodlo.y-cel.y)>0?-1:1) :0;
	

	WSPOLRZEDNE_PLANSZY aktualne(zrodlo.x,zrodlo.y);

	if(krokiX==krokiY||krokiX==0||krokiY==0)
		do //Poruszamy sie od zrodla do celu, sprawdzajac co napotkamy po drodze
		{
			aktualne.x+=1*dx; //idziemy naprzod (ktorykolwiek to kierunek...)
			aktualne.y+=1*dy;
			if(Pole(aktualne)!=PUSTE) //jesli natrafiamy na przeszkode
				break; //przerywamy
			if(krokiX)
				krokiX--; //skracamy sciezke do przejscia
			if(krokiY)
				krokiY--; 
		}
		while(krokiX||krokiY);
	else false;

	//Sprawdzamy czy doszlismy do konca sciezki
	if(!krokiX	&& !krokiY)
	{
		//sprawdzamy czy jestesmy na krawedzi lub czy natrafiamy na piona przeciwnika
		if((aktualne.x+dx)<0||(aktualne.x+dx)==rozmiarBokuPlanszy||
			(aktualne.y+dy)<0||(aktualne.y+dy)==rozmiarBokuPlanszy||
			Pole(WSPOLRZEDNE_PLANSZY(aktualne.x+dx,aktualne.y+dy))!=PUSTE)
		{
			//poruszamy sie
			return true;
		}
		else false;
	}
	else false;
	return false;
}

int PlanszaWirtualna::IloscDostepnychPionow(TURA gracz)
{
	int ilosc=0;
	for(int x=0;x<rozmiarBokuPlanszy;x++) 
		for(int y=0;y<rozmiarBokuPlanszy;y++)
			if(plansza[Indeks(WSPOLRZEDNE_PLANSZY(x,y))]==gracz)
				ilosc++;
	return ilosc;

}


void Plansza::AnimujRuch(WSPOLRZEDNE_PLANSZY zrodlo, WSPOLRZEDNE_PLANSZY cel, TURA gracz)
{
	int x=WspolrzedneEkranowe(zrodlo).x+szerokoscPola/2;
	int y=WspolrzedneEkranowe(zrodlo).y+szerokoscPola/2;

	int dx=WspolrzedneEkranowe(zrodlo).x-WspolrzedneEkranowe(cel).x>0?-1:1;
	int dy=WspolrzedneEkranowe(zrodlo).y-WspolrzedneEkranowe(cel).y>0?-1:1;
	this->Rysuj();

	ALLEGRO_BITMAP * kopiaEkranu=al_clone_bitmap(al_get_backbuffer());
	do
	{
		al_draw_bitmap(kopiaEkranu,0,0,0);
		al_draw_filled_circle((x),
			y,szerokoscPola/2,
			gracz==GRACZ_1?al_map_rgb(0,255,0):al_map_rgb(0,0,255));
		if(x!=WspolrzedneEkranowe(cel).x+szerokoscPola/2)
			x+=dx;
		if(y!=WspolrzedneEkranowe(cel).y+szerokoscPola/2)
			y+=dy;
		al_rest(0.001);
		al_flip_display();
	}
	while(x!=WspolrzedneEkranowe(cel).x+szerokoscPola/2||y!=WspolrzedneEkranowe(cel).y+szerokoscPola/2);
	al_destroy_bitmap(kopiaEkranu);
}


bool_ Plansza::WykonajRuch(WSPOLRZEDNE_PLANSZY zrodlo, WSPOLRZEDNE_PLANSZY cel, TURA gracz)
{
	if (SprawdzRuch(zrodlo,cel,gracz))
	{
			plansza[Indeks(zrodlo)]=PUSTE;
			AnimujRuch(zrodlo,cel,gracz);
			plansza[Indeks(cel)]=gracz;
			Przejmij(cel,gracz);
			this->Rysuj();
			al_flip_display();
			wykonaneRuchy.push_front(std::make_pair(gracz,RUCH(zrodlo,cel)));
			return true;
	}
	else return false;
}




bool_ PlanszaWirtualna::WykonajRuch(WSPOLRZEDNE_PLANSZY zrodlo, WSPOLRZEDNE_PLANSZY cel, TURA gracz)
{
	if (SprawdzRuch(zrodlo,cel,gracz))
	{
			plansza[Indeks(zrodlo)]=PUSTE;
			plansza[Indeks(cel)]=gracz;
			Przejmij(cel,gracz);
			return true;
	}
	else return false;
}

void PlanszaWirtualna::Przejmij(WSPOLRZEDNE_PLANSZY wspolrzedne, TURA gracz)
{
	if(wspolrzedne.x!=0) //sprawdzamy czy nie jestesmy na krawedzi
		if(plansza[Indeks(WSPOLRZEDNE_PLANSZY(wspolrzedne.x-1,wspolrzedne.y))]==-gracz)
			plansza[Indeks(WSPOLRZEDNE_PLANSZY(wspolrzedne.x-1,wspolrzedne.y))]=gracz;
	if (wspolrzedne.x!=rozmiarBokuPlanszy-1)
		if(plansza[Indeks(WSPOLRZEDNE_PLANSZY(wspolrzedne.x+1,wspolrzedne.y))]==-gracz)
			plansza[Indeks(WSPOLRZEDNE_PLANSZY(wspolrzedne.x+1,wspolrzedne.y))]=gracz;
	if(wspolrzedne.y!=0) //sprawdzamy czy nie jestesmy na krawedzi
		if(plansza[Indeks(WSPOLRZEDNE_PLANSZY(wspolrzedne.x,wspolrzedne.y-1))]==-gracz)
			plansza[Indeks(WSPOLRZEDNE_PLANSZY(wspolrzedne.x,wspolrzedne.y-1))]=gracz;
	if (wspolrzedne.y!=rozmiarBokuPlanszy-1)
		if(plansza[Indeks(WSPOLRZEDNE_PLANSZY(wspolrzedne.x,wspolrzedne.y+1))]==-gracz)
			plansza[Indeks(WSPOLRZEDNE_PLANSZY(wspolrzedne.x,wspolrzedne.y+1))]=gracz;
}

int PlanszaWirtualna::IloscDostepnychRuchow(TURA gracz)
{
	int ilosc=0;
	for(int x=0;x<rozmiarBokuPlanszy;x++) 
		for(int y=0;y<rozmiarBokuPlanszy;y++)
			if(plansza[Indeks(WSPOLRZEDNE_PLANSZY(x,y))]==gracz)
				for (int dx=-1;dx<2;dx++)
					for(int dy=-1;dy<2;dy++)
						if(x+dx!=-1&&x+dx!=rozmiarBokuPlanszy&&y+dy!=-1&&y+dy!=rozmiarBokuPlanszy)
							if(plansza[Indeks(WSPOLRZEDNE_PLANSZY(x+dx,y+dy))]==PUSTE)
								ilosc++;


	return ilosc;
}
bool comp(RUCH x,RUCH  y) { return x.zrodlo.x>y.zrodlo.x||x.zrodlo.y>y.zrodlo.y||x.cel.y>y.cel.y;};


std::vector<RUCH> PlanszaWirtualna::GenerujRuchy(TURA gracz)
{
	std::vector<RUCH> wygenerowaneRuchy;
	std::vector<RUCH> tymczasoweRuchy;
	
	wygenerowaneRuchy.reserve(rozmiarBokuPlanszy*2*8);
	tymczasoweRuchy.reserve(rozmiarBokuPlanszy*2*8);
	for(int x=0;x<rozmiarBokuPlanszy;x++) 
		for(int y=0;y<rozmiarBokuPlanszy;y++)
			if(plansza[Indeks(WSPOLRZEDNE_PLANSZY(x,y))]==gracz)
				for (int dx=-1;dx<2;dx++)
					for(int dy=-1;dy<2;dy++)
						if(x+dx!=-1&&x+dx!=rozmiarBokuPlanszy&&y+dy!=-1&&y+dy!=rozmiarBokuPlanszy)
							if(plansza[Indeks(WSPOLRZEDNE_PLANSZY(x+dx,y+dy))]==PUSTE)
							{
								int tempX=x;
								int tempY=y;
								bool_ ruchMozliwy=false;
								while(!ruchMozliwy&&tempX+dx!=-1&&tempX+dx!=rozmiarBokuPlanszy&&tempY+dy!=-1&&tempY+dy!=rozmiarBokuPlanszy)
								{
									tempX+=dx;
									tempY+=dy;
									ruchMozliwy=SprawdzRuch(WSPOLRZEDNE_PLANSZY(x,y),WSPOLRZEDNE_PLANSZY(tempX,tempY),gracz);
								}
								if (ruchMozliwy)
								{
								
									tymczasoweRuchy.push_back(RUCH(WSPOLRZEDNE_PLANSZY(x,y),WSPOLRZEDNE_PLANSZY(tempX,tempY)));							

								}

							}

	while(tymczasoweRuchy.size())
	{
		int wylosowana=rand()%tymczasoweRuchy.size();
		wygenerowaneRuchy.push_back(tymczasoweRuchy[wylosowana]);
		tymczasoweRuchy.erase(tymczasoweRuchy.begin()+wylosowana);
	}
	return wygenerowaneRuchy;
}